package com.gitee.wsl.time.chinese.bean

import com.gitee.wsl.time.chinese.Lunar
import com.gitee.wsl.time.chinese.bean.eightchar.Yun
import com.gitee.wsl.time.chinese.util.LunarUtil
import com.gitee.wsl.time.chinese.util.LunarUtil.find

/**
 * 八字
 *
 * @author 6tail
 */
class EightChar(
    /**
     * 阴历
     */
    var lunar: Lunar,
) {
    /**
     * 流派，2晚子时日柱按当天，1晚子时日柱按明天
     */
    var sect: Int = 2
        /**
         * 设置流派
         *
         * @param sect 流派，2晚子时日柱按当天，1晚子时日柱按明天，其他值默认为2
         */
        set(value) {
            field = if (1 == value) 1 else 2
        }

    override fun toString(): String {
        return this.year + " " + this.month + " " + this.day + " " + this.time
    }

    /**
     * 获取流派
     *
     * @return 流派，2晚子时日柱按当天，1晚子时日柱按明天
     */
//    fun getSect(): Int {
//        return sect
//    }

    /**
     * 设置流派
     *
     * @param sect 流派，2晚子时日柱按当天，1晚子时日柱按明天，其他值默认为2
     */
//    fun setSect(sect: Int) {
//        this.sect = if (1 == sect) 1 else 2
//    }

    val year: String
        /**
         * 获取年柱
         *
         * @return 年柱
         */
        get() = lunar.yearInGanZhiExact

    val yearGan: String
        /**
         * 获取年干
         *
         * @return 天干
         */
        get() = lunar.yearGanExact

    val yearZhi: String
        /**
         * 获取年支
         *
         * @return 地支
         */
        get() = lunar.yearZhiExact

    val yearHideGan: List<String?>
        /**
         * 获取年柱地支藏干，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 天干
         */
        get() = LunarUtil.ZHI_HIDE_GAN.get(this.yearZhi)!!

    val yearWuXing: String
        /**
         * 获取年柱五行
         *
         * @return 五行
         */
        get() = LunarUtil.WU_XING_GAN.get(this.yearGan) + LunarUtil.WU_XING_ZHI.get(this.yearZhi)

    val yearNaYin: String
        /**
         * 获取年柱纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.year)!!

    val yearShiShenGan: String
        /**
         * 获取年柱天干十神
         *
         * @return 十神
         */
        get() = LunarUtil.SHI_SHEN.get(this.dayGan + this.yearGan)!!

    private fun getShiShenZhi(zhi: String): List<String> {
        val hideGan = LunarUtil.ZHI_HIDE_GAN.get(zhi)!!
        val l = ArrayList<String>(hideGan.size)
        for (gan in hideGan) {
            l.add(LunarUtil.SHI_SHEN.get(this.dayGan + gan)!!)
        }
        return l
    }

    val yearShiShenZhi: List<String>
        /**
         * 获取年柱地支十神，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 十神
         */
        get() = getShiShenZhi(this.yearZhi)

    val dayGanIndex: Int
        /**
         * 获取日干下标
         *
         * @return 日干下标，0-9
         */
        get() = if (2 == sect) lunar.dayGanIndexExact2 else lunar.dayGanIndexExact

    val dayZhiIndex: Int
        /**
         * 获取日支下标
         *
         * @return 日支下标，0-11
         */
        get() = if (2 == sect) lunar.dayZhiIndexExact2 else lunar.dayZhiIndexExact

    private fun getDiShi(zhiIndex: Int): String {
        var index = CHANG_SHENG_OFFSET.get(this.dayGan)!! + (if (this.dayGanIndex % 2 == 0) zhiIndex else -zhiIndex)
        if (index >= 12) {
            index -= 12
        }
        if (index < 0) {
            index += 12
        }
        return CHANG_SHENG[index]
    }

    val yearDiShi: String
        /**
         * 获取年柱地势（长生十二神）
         *
         * @return 地势
         */
        get() = getDiShi(lunar.yearZhiIndexExact)

    val month: String
        /**
         * 获取月柱
         *
         * @return 月柱
         */
        get() = lunar.monthInGanZhiExact

    val monthGan: String
        /**
         * 获取月干
         *
         * @return 天干
         */
        get() = lunar.monthGanExact

    val monthZhi: String
        /**
         * 获取月支
         *
         * @return 地支
         */
        get() = lunar.monthZhiExact

    val monthHideGan: List<String>
        /**
         * 获取月柱地支藏干，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 天干
         */
        get() = LunarUtil.ZHI_HIDE_GAN.get(this.monthZhi)!!

    val monthWuXing: String
        /**
         * 获取月柱五行
         *
         * @return 五行
         */
        get() = LunarUtil.WU_XING_GAN.get(this.monthGan) + LunarUtil.WU_XING_ZHI.get(this.monthZhi)

    val monthNaYin: String
        /**
         * 获取月柱纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.month)!!

    val monthShiShenGan: String
        /**
         * 获取月柱天干十神
         *
         * @return 十神
         */
        get() = LunarUtil.SHI_SHEN.get(this.dayGan + this.monthGan)!!

    val monthShiShenZhi: List<String?>
        /**
         * 获取月柱地支十神，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 十神
         */
        get() = getShiShenZhi(this.monthZhi)

    val monthDiShi: String
        /**
         * 获取月柱地势（长生十二神）
         *
         * @return 地势
         */
        get() = getDiShi(lunar.monthZhiIndexExact)

    val day: String
        /**
         * 获取日柱
         *
         * @return 日柱
         */
        get() = if (2 == sect) lunar.dayInGanZhiExact2 else lunar.dayInGanZhiExact

    val dayGan: String
        /**
         * 获取日干
         *
         * @return 天干
         */
        get() = if (2 == sect) lunar.dayGanExact2 else lunar.dayGanExact

    val dayZhi: String
        /**
         * 获取日支
         *
         * @return 地支
         */
        get() = if (2 == sect) lunar.dayZhiExact2 else lunar.dayZhiExact

    val dayHideGan: List<String?>
        /**
         * 获取日柱地支藏干，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 天干
         */
        get() = LunarUtil.ZHI_HIDE_GAN.get(this.dayZhi)!!

    val dayWuXing: String
        /**
         * 获取日柱五行
         *
         * @return 五行
         */
        get() = LunarUtil.WU_XING_GAN.get(this.dayGan) + LunarUtil.WU_XING_ZHI.get(this.dayZhi)

    val dayNaYin: String
        /**
         * 获取日柱纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.day)!!

    val dayShiShenGan: String
        /**
         * 获取日柱天干十神，也称日元、日干
         *
         * @return 十神
         */
        get() = "日主"

    val dayShiShenZhi: List<String?>
        /**
         * 获取日柱地支十神，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 十神
         */
        get() = getShiShenZhi(this.dayZhi)

    val dayDiShi: String
        /**
         * 获取日柱地势（长生十二神）
         *
         * @return 地势
         */
        get() = getDiShi(this.dayZhiIndex)

    val time: String
        /**
         * 获取时柱
         *
         * @return 时柱
         */
        get() = lunar.timeInGanZhi

    val timeGan: String
        /**
         * 获取时干
         *
         * @return 天干
         */
        get() = lunar.timeGan

    val timeZhi: String
        /**
         * 获取时支
         *
         * @return 地支
         */
        get() = lunar.timeZhi

    val timeHideGan: List<String>
        /**
         * 获取时柱地支藏干，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 天干
         */
        get() = LunarUtil.ZHI_HIDE_GAN.get(this.timeZhi)!!

    val timeWuXing: String
        /**
         * 获取时柱五行
         *
         * @return 五行
         */
        get() = LunarUtil.WU_XING_GAN.get(lunar.timeGan) + LunarUtil.WU_XING_ZHI.get(lunar.timeZhi)

    val timeNaYin: String
        /**
         * 获取时柱纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.time)!!

    val timeShiShenGan: String
        /**
         * 获取时柱天干十神
         *
         * @return 十神
         */
        get() = LunarUtil.SHI_SHEN.get(this.dayGan + this.timeGan)!!

    val timeShiShenZhi: List<String?>
        /**
         * 获取时柱地支十神，由于藏干分主气、余气、杂气，所以返回结果可能为1到3个元素
         *
         * @return 十神
         */
        get() = getShiShenZhi(this.timeZhi)

    val timeDiShi: String
        /**
         * 获取时柱地势（长生十二神）
         *
         * @return 地势
         */
        get() = getDiShi(lunar.timeZhiIndex)

    val taiYuan: String
        /**
         * 获取胎元
         *
         * @return 胎元
         */
        get() {
            var ganIndex = lunar.monthGanIndexExact + 1
            if (ganIndex >= 10) {
                ganIndex -= 10
            }
            var zhiIndex = lunar.monthZhiIndexExact + 3
            if (zhiIndex >= 12) {
                zhiIndex -= 12
            }
            return LunarUtil.GAN[ganIndex + 1] + LunarUtil.ZHI[zhiIndex + 1]
        }

    val taiYuanNaYin: String
        /**
         * 获取胎元纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.taiYuan)!!

    val taiXi: String
        /**
         * 获取胎息
         *
         * @return 胎息
         */
        get() {
            val ganIndex = if (2 == sect) lunar.dayGanIndexExact2 else lunar.dayGanIndexExact
            val zhiIndex = if (2 == sect) lunar.dayZhiIndexExact2 else lunar.dayZhiIndexExact
            return LunarUtil.HE_GAN_5[ganIndex] + LunarUtil.HE_ZHI_6[zhiIndex]
        }

    val taiXiNaYin: String
        /**
         * 获取胎息纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.taiXi)!!

    val mingGong: String
        /**
         * 获取命宫
         *
         * @return 命宫
         */
        get() {
            val monthZhiIndex = find(this.monthZhi, MONTH_ZHI, 0)
            val timeZhiIndex = find(this.timeZhi, MONTH_ZHI, 0)
            var offset = monthZhiIndex + timeZhiIndex
            offset = (if (offset >= 14) 26 else 14) - offset
            var ganIndex = (lunar.yearGanIndexExact + 1) * 2 + offset
            while (ganIndex > 10) {
                ganIndex -= 10
            }
            return LunarUtil.GAN[ganIndex] + MONTH_ZHI[offset]
        }

    val mingGongNaYin: String
        /**
         * 获取命宫纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.mingGong)!!

    val shenGong: String
        /**
         * 获取身宫
         *
         * @return 身宫
         */
        get() {
            val monthZhiIndex = find(this.monthZhi, MONTH_ZHI, 0)
            val timeZhiIndex = find(this.timeZhi, LunarUtil.ZHI, 0)
            var offset = monthZhiIndex + timeZhiIndex
            if (offset > 12) {
                offset -= 12
            }
            var ganIndex = (lunar.yearGanIndexExact + 1) * 2 + offset
            while (ganIndex > 10) {
                ganIndex -= 10
            }
            return LunarUtil.GAN[ganIndex] + MONTH_ZHI[offset]
        }

    val shenGongNaYin: String
        /**
         * 获取身宫纳音
         *
         * @return 纳音
         */
        get() = LunarUtil.NAYIN.get(this.shenGong)!!

    /**
     * 使用默认流派1获取运
     *
     * @param gender 性别：1男，0女
     * @return 运
     */
    fun getYun(gender: Int): Yun {
        return getYun(gender, 1)
    }

    /**
     * 获取运
     *
     * @param gender 性别：1男，0女
     * @param sect 流派，1按天数和时辰数计算，3天1年，1天4个月，1时辰10天；2按分钟数计算
     * @return 运
     */
    fun getYun(gender: Int, sect: Int): Yun {
        return Yun(this, gender, sect)
    }

    val yearXun: String
        /**
         * 获取年柱所在旬
         *
         * @return 旬
         */
        get() = lunar.yearXunExact

    val yearXunKong: String
        /**
         * 获取年柱旬空(空亡)
         *
         * @return 旬空(空亡)
         */
        get() = lunar.yearXunKongExact

    val monthXun: String
        /**
         * 获取月柱所在旬
         *
         * @return 旬
         */
        get() = lunar.monthXunExact

    val monthXunKong: String
        /**
         * 获取月柱旬空(空亡)
         *
         * @return 旬空(空亡)
         */
        get() = lunar.monthXunKongExact

    val dayXun: String
        /**
         * 获取日柱所在旬
         *
         * @return 旬
         */
        get() = if (2 == sect) lunar.dayXunExact2 else lunar.dayXunExact

    val dayXunKong: String
        /**
         * 获取日柱旬空(空亡)
         *
         * @return 旬空(空亡)
         */
        get() = if (2 == sect) lunar.dayXunKongExact2 else lunar.dayXunKongExact

    val timeXun: String
        /**
         * 获取时柱所在旬
         *
         * @return 旬
         */
        get() = lunar.timeXun

    val timeXunKong: String
        /**
         * 获取时柱旬空(空亡)
         *
         * @return 旬空(空亡)
         */
        get() = lunar.timeXunKong

    companion object {
        /**
         * 月支，按正月起寅排列
         */
        private val MONTH_ZHI =
            arrayOf<String>("", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥", "子", "丑")

        /**
         * 长生十二神
         */
        val CHANG_SHENG: Array<String> =
            arrayOf<String>("长生", "沐浴", "冠带", "临官", "帝旺", "衰", "病", "死", "墓", "绝", "胎", "养")

        /**
         * 长生十二神日干偏移值，五阳干顺推，五阴干逆推
         */
        private val CHANG_SHENG_OFFSET: Map<String, Int> = mutableMapOf<String, Int>().apply{
                //阳
                put("甲", 1)
                put("丙", 10)
                put("戊", 10)
                put("庚", 7)
                put("壬", 4)
                //阴
                put("乙", 6)
                put("丁", 9)
                put("己", 9)
                put("辛", 0)
                put("癸", 3)
        }

        fun fromLunar(lunar: Lunar): EightChar {
            return EightChar(lunar)
        }
    }
}
